from datetime import datetime
from typing import Dict, Any
from bson import ObjectId
from sqlalchemy.ext.asyncio import AsyncSession
from app.config import settings
from app.services.llm import generate_section_text
from app.services.scoring import compute_evaluation_total
from app.models import EvaluationReportHeader
import re
from datetime import datetime


def _storage_path(filename: str) -> str:
    p = settings.reports_dir / filename
    return str(p)


def _safe_filename(name: str) -> str:
    base = re.sub(r"[^\w\-\u4e00-\u9fff]+", "_", name).strip("._ ")
    return base or "report"


async def generate_report_docx(session: AsyncSession, mongo_db, activity, evaluation) -> Dict[str, Any]:
    # 计算并更新总分
    total = await compute_evaluation_total(session, str(evaluation.id))
    evaluation.score_total = total

    # 生成占位章节文本
    variables = {
        "title": "概述",
        "activity_name": activity.name,
        "score_total": float(total),
    }
    text = generate_section_text(settings.LLM_MODEL, variables)

    # 生成简单 DOCX（占位）：包含标题与概述段落
    try:
        from docx import Document
    except Exception:
        Document = None

    filename = f"report_{evaluation.id}.docx"
    file_path = _storage_path(filename)
    if Document:
        doc = Document()
        doc.add_heading(f"{activity.name} 评估报告", level=1)
        doc.add_paragraph(text)
        doc.save(file_path)
    else:
        # 若未安装python-docx，仍返回一个占位路径
        with open(file_path, "w", encoding="utf-8") as f:
            f.write(text)

    # 写入 Mongo reports 集合
    report_doc = {
        "activity_id": str(activity.id),
        "evaluation_id": str(evaluation.id),
        "template_version_code": settings.REPORT_TEMPLATE_VERSION_CODE,
        "docx": {
            "file_url": file_path,
            "generated_at": datetime.utcnow(),
            "generated_by": "system",
        },
        "sections": [
            {
                "section_no": "1",
                "section_name": "概述",
                "level": 1,
                "style": "Heading 1",
                "required": True,
                "status": "draft",
                "binding": {
                    "activity_fields": ["name", "location_admin", "time_start", "time_end"],
                    "indicator_item_ids": [],
                    "indicator_theme_ids": [],
                    "event_ids": [],
                    "event_filters": {},
                    "computed_metrics": {
                        "score_total": float(total),
                        "deductions": [],
                        "veto_hit": False,
                    },
                },
                "content": {
                    "raw_text": text,
                    "edited_text": "",
                    "tables": [],
                    "images": [],
                },
                "sources": [],
                "llm": {
                    "model": settings.LLM_MODEL,
                    "prompt": "auto",
                    "variables": variables,
                    "temperature": 0.2,
                    "tokens": {"input": 0, "output": 0},
                    "warnings": [],
                },
                "audit": {
                    "created_at": datetime.utcnow(),
                    "created_by": "system",
                    "updated_at": datetime.utcnow(),
                    "updated_by": "system",
                },
            }
        ],
        "status": "draft",
        "audit": {
            "created_at": datetime.utcnow(),
            "created_by": "system",
            "updated_at": datetime.utcnow(),
            "updated_by": "system",
        },
    }

    inserted = await mongo_db.reports.insert_one(report_doc)
    report_doc["_id"] = inserted.inserted_id if isinstance(inserted.inserted_id, ObjectId) else inserted.inserted_id
    return report_doc


async def export_version_to_docx(session: AsyncSession, mongo_db, version, items: list[dict]) -> dict:
    try:
        from docx import Document
    except Exception:
        Document = None
    hdr = await session.get(EvaluationReportHeader, version.report_id)
    title = _safe_filename(f"{hdr.name}_v{version.version_no}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}") if hdr else _safe_filename(f"report_v{version.version_no}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}")
    filename = f"{title}.docx"
    file_path = _storage_path(filename)
    if Document:
        doc = Document()
        for it in items:
            title = f"{str(it.get('section_no') or '')} {str(it.get('section_name') or '')}".strip()
            lvl = int(it.get('level') or 1)
            doc.add_heading(title, level=max(1, min(lvl, 3)))
            doc.add_paragraph(str(it.get('text') or ''))
        doc.save(file_path)
    else:
        with open(file_path, "w", encoding="utf-8") as f:
            for it in items:
                title = f"{str(it.get('section_no') or '')} {str(it.get('section_name') or '')}".strip()
                f.write(title + "\n")
                f.write(str(it.get('text') or '') + "\n\n")
    rel_path = f"/static/reports/{filename}"
    await mongo_db.reports.update_one({"_id": ObjectId(str(version.mongo_report_id))}, {"$set": {"exports.docx": {"rel_path": rel_path, "generated_at": datetime.utcnow()}}})
    return {"file_url": file_path, "rel_path": rel_path}


async def export_version_to_pdf(session: AsyncSession, mongo_db, version, items: list[dict]) -> dict:
    hdr = await session.get(EvaluationReportHeader, version.report_id)
    title = _safe_filename(f"{hdr.name}_v{version.version_no}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}") if hdr else _safe_filename(f"report_v{version.version_no}_{datetime.utcnow().strftime('%Y%m%d%H%M%S')}")
    filename = f"{title}.pdf"
    file_path = _storage_path(filename)
    try:
        from reportlab.lib.pagesizes import A4
        from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
        from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer
        from reportlab.pdfbase import pdfmetrics
        from reportlab.pdfbase.ttfonts import TTFont
        from reportlab.pdfbase.cidfonts import UnicodeCIDFont
    except Exception:
        with open(file_path, "w", encoding="utf-8") as f:
            for it in items:
                title = f"{str(it.get('section_no') or '')} {str(it.get('section_name') or '')}".strip()
                f.write(title + "\n")
                f.write(str(it.get('text') or '') + "\n\n")
        rel_path = f"/static/reports/{filename}"
        await mongo_db.reports.update_one({"_id": ObjectId(str(version.mongo_report_id))}, {"$set": {"exports.pdf": {"rel_path": rel_path, "generated_at": datetime.utcnow()}}})
        return {"file_url": file_path, "rel_path": rel_path}
    doc = SimpleDocTemplate(file_path, pagesize=A4)
    styles = getSampleStyleSheet()
    font_name = None
    try:
        if settings.PDF_FONT_PATH:
            pdfmetrics.registerFont(TTFont("CustomChinese", settings.PDF_FONT_PATH))
            font_name = "CustomChinese"
    except Exception:
        pass
    if not font_name:
        try:
            pdfmetrics.registerFont(UnicodeCIDFont("STSong-Light"))
            font_name = "STSong-Light"
        except Exception:
            pass
    if not font_name:
        try:
            pdfmetrics.registerFont(TTFont("DejaVuSans", "DejaVuSans.ttf"))
            font_name = "DejaVuSans"
        except Exception:
            font_name = "Helvetica"
    styles.add(ParagraphStyle('CHeading1', parent=styles['Heading1'], fontName=font_name))
    styles.add(ParagraphStyle('CHeading2', parent=styles['Heading2'], fontName=font_name))
    styles.add(ParagraphStyle('CHeading3', parent=styles['Heading3'], fontName=font_name))
    styles.add(ParagraphStyle('CBody', parent=styles['BodyText'], fontName=font_name))
    story = []
    for it in items:
        title = f"{str(it.get('section_no') or '')} {str(it.get('section_name') or '')}".strip()
        lvl = int(it.get('level') or 1)
        style = styles['CHeading1'] if lvl == 1 else styles['CHeading2'] if lvl == 2 else styles['CHeading3']
        story.append(Paragraph(title, style))
        story.append(Spacer(1, 12))
        story.append(Paragraph(str(it.get('text') or ''), styles['CBody']))
        story.append(Spacer(1, 18))
    doc.build(story)
    rel_path = f"/static/reports/{filename}"
    await mongo_db.reports.update_one({"_id": ObjectId(str(version.mongo_report_id))}, {"$set": {"exports.pdf": {"rel_path": rel_path, "generated_at": datetime.utcnow()}}})
    return {"file_url": file_path, "rel_path": rel_path}
